package com.fintech.pangu.actuate.metrics.util;

import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.DistributionSummary;
import io.micrometer.core.instrument.Gauge;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Metrics;
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.Tags;
import io.micrometer.core.instrument.Timer;

import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @Description: Metrics工具类
 * @Author xiexiaole
 * @Date 2019/12/25 10:37
 */
public class MetricsUtil {


    private static final Map<String, AtomicInteger> integerMap = new ConcurrentHashMap<>();

    /**
     * timed
     * @param metricName
     * @param description
     * @param tags
     * @param publishPercentileHistogram
     * @param percentiles
     */
    public static Timer recordTime(String metricName, String description,Tags tags,
                                  boolean publishPercentileHistogram,
                                  double ...percentiles) {
        Timer register = Timer.builder(metricName)
                .description(description)
                .tags(tags)
                .publishPercentileHistogram(publishPercentileHistogram)
                .publishPercentiles(percentiles)
                .register(getRegistry());
        return register;
    }
    public static Timer recordTime(String metricName, String description, Tags tags ) {
        return recordTime(metricName,description,tags,false,0);
    }
    public static Timer recordTime(String metricName, String description) {
        return recordTime(metricName,description,null,false,0);
    }

    /**
     * Counter
     * @param metricName
     * @param description
     * @param tags
     * @param baseUnit
     * @return
     */
    public static Counter recordCounter(String metricName, String description, String baseUnit, Tags tags){
        Counter register = Counter.builder(metricName)
                .description(description)
                .tags(tags)
                .baseUnit(baseUnit)
                .register(getRegistry());
        return register;
    }
    public static Counter recordCounter(String metricName, String description, Tags tags){
        return recordCounter(metricName, description,null, tags);
    }
    public static Counter recordCounter(String metricName, String description){
        return recordCounter(metricName, description,null,null);
    }

    /**
     * Gauge
     * @param metricName
     * @param description
     * @param tags
     * @param baseUnit
     * @return
     */
    public static AtomicInteger recordGauge(String metricName, String description, String baseUnit, String[] tagArr, Tags tags){
        String key = generatorKey(metricName, tagArr, tags);
        AtomicInteger gaugeValue = getGaugeValue(key);
        if(gaugeValue == null) {
            gaugeValue = new AtomicInteger(0);
            putGaugeValue(key, gaugeValue);
        }
        Gauge.builder(metricName, gaugeValue, AtomicInteger::get)
                .tags(tags)
                .tags(tagArr)
                .baseUnit(baseUnit)
                .description(description)
                .register(getRegistry());
        return gaugeValue;
    }
    public static AtomicInteger recordGauge(String metricName, String description, String baseUnit,  Tags tags){
        return recordGauge(metricName,description,baseUnit,null,tags);
    }

    public static AtomicInteger recordGauge(String metricName, String description, String[] tags){
        return recordGauge(metricName, description,null, tags,null);
    }
    public static AtomicInteger recordGauge(String metricName, String description, Tags tags){
        return recordGauge(metricName, description,null, tags);
    }
    public static AtomicInteger recordGauge(String metricName, String description){
        return recordGauge(metricName, description, null,  null);
    }

    /**
     * 分布样本跟踪
     * @param metricName
     * @param description
     * @param tags
     * @param percentiles
     * @return
     */
    public static DistributionSummary recordDistributionSummary(String metricName,String description,Tags tags,double ...percentiles){
        DistributionSummary summary = DistributionSummary.builder(metricName)
                .tags(tags)
                .publishPercentiles(percentiles)
                .description(description)
                .register(getRegistry());
        return summary;
    }
    public static DistributionSummary recordDistributionSummary(String metricName,String description,double ...percentiles) {
        return recordDistributionSummary(metricName, description, null, percentiles);
    }

    protected static MeterRegistry getRegistry(){
        return Metrics.globalRegistry;
    }

    protected static AtomicInteger getGaugeValue(String key) {
        return integerMap.get(key);
    }
    protected static void putGaugeValue(String key, AtomicInteger value){
        integerMap.put(key, value);
    }

    private static String generatorKey(String metricName,String [] tagArr, Tags tags){
        StringBuilder builder = new StringBuilder(metricName);
        if(tagArr != null && tagArr.length > 0){
            int length = tagArr.length % 2 == 0 ? tagArr.length : tagArr.length - 1;
            for (int i = 0; i < length; i+=2) {
                builder.append("_").append(tagArr[i]).append(":").append(tagArr[i+1]);
            }

        }
        if(tags != null){
            Iterator<Tag> iterator = tags.iterator();
            while (iterator.hasNext()){
                Tag next = iterator.next();
                builder.append("_").append(next.getKey()).append(":").append(next.getValue());
            }
        }
        return builder.toString();
    }

}
